﻿using System.Threading;
using System;
using Honeycomb.Protocol;

namespace Honeycomb.Core.Client
{
    /// <summary>
    /// TaskExecutionThread is responsible for keeping one core busy with tasks.
    /// </summary>
    sealed class TaskExecutionThread : IDisposable
    {
        /// <summary>
        /// Thread used for task processing.
        /// </summary>
        private readonly Thread thread;

        /// <summary>
        /// Reference to task schedulers unprocessed task queue.
        /// </summary>
        private readonly BlockingQueue<TaskBase> taskQueue; 

        /// <summary>
        /// Reference to task schedulers result queue.
        /// </summary>
        private readonly Queue<TaskExecutionResult> resultQueue;

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="taskQueue">Task schedulers task queue.</param>
        /// <param name="resultQueue">Task schedulers result queue.</param>
        public TaskExecutionThread(BlockingQueue<TaskBase> taskQueue, Queue<TaskExecutionResult> resultQueue)
        {
            this.taskQueue = taskQueue;
            this.resultQueue = resultQueue;

            // Start execution thread.
            thread = new Thread(Execute) { Priority = ThreadPriority.Lowest };
            thread.Start();
        }

        /// <summary>
        /// Internal execution thread.
        /// </summary>
        private void Execute()
        {
            for (; ; )
            {
                // Get one task from the task schedulers task queue.
                TaskBase task = taskQueue.Dequeue();
                object result = null;
                Exception exception = null;
                
                try
                {
                    // Execute task.
                    result = task.Execute();
                }
                catch (ThreadAbortException)
                {
                    // The thread is aborted upon application shutdown.
                    return;
                }
                catch (Exception ex)
                {
                    exception = ex;
                }

                // Enqueue the result in the task schedulers result queue.
                resultQueue.Enqueue(new TaskExecutionResult { Task = task, Result = result, Exception = exception });
            }
        }

        /// <summary>
        /// Dispose.
        /// </summary>
        public void Dispose()
        {
            thread.Abort();
        }
    }
}